package web

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type QueryParam url.Values

var ParamNotFoundError = errors.New("param not found")

type QueryParamError struct {
	errMsg string
	e      error
}

func (q *QueryParamError) Error() string {
	return q.errMsg
}

func (q *QueryParamError) Unwrap() error {
	return q.e
}

func newQueryParamError(msg string, e error) *QueryParamError {
	return &QueryParamError{
		errMsg: msg,
		e:      e,
	}
}

func (q *QueryParam) Get(key string) string {
	vs := (*url.Values)(q)
	v := vs.Get(key)
	return strings.Trim(v, "\"")
}

func (q *QueryParam) GetTime(key string) (*time.Time, error) {
	vs := (*url.Values)(q)
	if !vs.Has(key) {
		return nil, newQueryParamError(fmt.Sprintf("%s not exist", key), ParamNotFoundError)
	}
	v := q.Get(key)
	t, err := time.Parse(time.RFC3339, v)
	if err != nil {
		return nil, err
	}
	return &t, nil
}

func (q *QueryParam) GetFloat(key string) (float64, error) {
	vs := (*url.Values)(q)
	if !vs.Has(key) {
		return 0, newQueryParamError(fmt.Sprintf("%s not exist", key), ParamNotFoundError)
	}
	v := q.Get(key)
	f, err := strconv.ParseFloat(v, 64)
	return f, err
}

func (q *QueryParam) GetInt(key string) (int64, error) {
	vs := (*url.Values)(q)
	if !vs.Has(key) {
		return 0, newQueryParamError(fmt.Sprintf("%s not exist", key), ParamNotFoundError)
	}
	v := q.Get(key)
	i, err := strconv.ParseInt(v, 10, 64)
	return i, err
}

func (q *QueryParam) GetByte(key string) (byte, error) {
	i, err := q.GetInt(key)
	if err != nil {
		return 0, err
	} else {
		return byte(i), err
	}
}

func (q *QueryParam) GetString(key string) (string, error) {
	vs := (*url.Values)(q)
	if !vs.Has(key) {
		return "", newQueryParamError(fmt.Sprintf("%s not exist", key), ParamNotFoundError)
	}
	v := q.Get(key)
	return v, nil
}

func (q *QueryParam) GetBool(key string) (bool, error) {
	vs := (*url.Values)(q)
	if !vs.Has(key) {
		return false, newQueryParamError(fmt.Sprintf("%s not exist", key), ParamNotFoundError)
	}
	v := q.Get(key)
	i, err := strconv.ParseInt(v, 10, 64)
	if err == nil {
		return i != 0, nil
	}
	return v == "true", nil
}
